"""Custom form field behaviours for different properties. """

#from django.db import models
from django.contrib.gis.db import models
from django import newforms as forms
from django.newforms.util import flatatt
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django.utils.html import escape
from django.conf import settings
from itertools import chain
from warnings import warn

class NoAgent(Exception): pass
class NoUniqueAgent(Exception): pass

class AgentMultipleWidget(forms.SelectMultiple):

    def render(self, name, value, attrs=None, choices=()):
        if value is None: value = []
        output = []
        final_attrs = self.build_attrs(attrs, name=name)
        output.append(u'<div class="jinput"><input type="text" name="%s" /></div>' % (name,))
        for option_value, option_label in chain(self.choices, choices):
            if option_value in value:
                output.append(u'<div class="jmultiple"><input type="hidden" name="%s" value="%s" /><pre>%s</pre></div>' % (name, escape(option_value), escape(option_label)))
        #output.append(u'<p><a class="notes" href="../../../../i"        
        return mark_safe(u''.join(output))

    def value_from_datadict(self, data, files, prefix):
        """Value supplied must match one existing in backend data, e.g. list of Agents."""
        from duetopia.register.models.meta import Agent

        values = data.getlist(prefix)
        return_values = []
        exception = None
        for v in values:
            if not v: continue
            try:
                v = int(v)
                if v not in return_values:
                    return_values.append(v)
            except ValueError:
                cw = { 'name__icontains' : v }
                agents = Agent.objects.filter(**cw)
                if len(agents) == 1:
                    return_values.append(agents[0].id)
                elif len(agents) == 0:
                    exception = NoAgent(v)
                else:
                    exception = NoUniqueAgent(agents)
        if exception is not None:
            raise exception

        # nice try
        # - <a href="../../../agent/add/">add agent</a>')
        return return_values

class AgentHiddenWidget(AgentMultipleWidget):
    input_type = 'hidden'
    is_hidden = True
    def render(self, name, value, attrs=None, choices=()):
        if value is None: value = []
        final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
        return mark_safe(u'\n'.join([(u'<input%s />' %
            flatatt(dict(value=force_unicode(v), **final_attrs)))
            for v in value]))

class AgentSearchForm(forms.ModelMultipleChoiceField):
    hidden_widget = AgentHiddenWidget
    def __init__(self, *av, **kwargs):
        defaults = { 'widget' : AgentMultipleWidget }
        defaults.update(kwargs)
        super(AgentSearchForm, self).__init__(*av, **defaults)

    def clean(self, value):
        for v in value:
            if not isinstance(v, int):
                raise forms.ValidationError(v)
        return value

class AgentField(models.ManyToManyField):
    def __init__(self, *av, **kw):
        from duetopia.register.models.meta import Agent
        super(AgentField, self).__init__(Agent, *av, **kw)
        self.help_text = kw.get('help_text', '')

    def formfield(self, **kwargs):
        defaults = { 'form_class' : AgentSearchForm }
        defaults.update(kwargs)
        return super(AgentField, self).formfield(**defaults)

# @@ keyword widget should be a more del.icio.us-style js autofill

class KeywordMultipleWidget(forms.SelectMultiple):

    def render(self, name, value, attrs=None, choices=()):
        if value is None: value = []
        output = []
        final_attrs = self.build_attrs(attrs, name=name)
        output.append(u'<div class="jinput"><input type="text" name="%s" /></div>' % (name,))
        for option_value, option_label in chain(self.choices, choices):
            if option_value in value:
                output.append(u'<div class="jmultiple"><input type="hidden" name="%s" value="%s" /><pre>%s</pre></div>' % (name, escape(option_value), escape(option_label)))
        return mark_safe(u''.join(output))

    def value_from_datadict(self, data, files, prefix):
        from duetopia.register.models.meta import Keyword

        values = data.getlist(prefix)
        return_values = []

        if 'LANGUAGE_CODE' in data: lang = data['LANGUAGE_CODE']
        else: lang = 'en'

        return_values = []
        for v in values:
            if not v: continue
            try:
                int(v)
                return_values.append(v)
            except ValueError:
                cw = { 'word' : v, 'lang' : lang }
                keyword, created = Keyword.objects.get_or_create(**cw)
                return_values.append(keyword.id)
        return return_values

class KeywordSearchForm(forms.ModelMultipleChoiceField):
    def __init__(self, *av, **kwargs):
        defaults = { 'widget' : KeywordMultipleWidget }
        defaults.update(kwargs)
        super(KeywordSearchForm, self).__init__(*av, **defaults)

class KeywordField(models.ManyToManyField):
    def __init__(self, *av, **kw):
        from duetopia.register.models.meta import Keyword
        super(KeywordField, self).__init__(Keyword, *av, **kw)
        self.help_text = kw.get('help_text', '')
    def formfield(self, **kwargs):
        defaults = { 'form_class' : KeywordSearchForm }
        defaults.update(kwargs)
        return super(KeywordField, self).formfield(**defaults)

# ParsedDateField is adapted from 
# http://www.djangosnippets.org/snippets/268/

from mx.DateTime import DateTimeFrom
from datetime import datetime

class ParseDateForm(forms.Field):
    """ Date field that accepts natural-language input
    Uses the DateUtil module to parse input.

    """
    def clean(self, value):
        super(ParseDateForm, self).clean(value)
        if value in (None, ''):
            return None
        if isinstance(value, datetime):
            return value
        try:
            return DateTimeFrom(str(value))
        except ValueError:
            raise forms.ValidationError(u'Enter a date thus: 2008-01-01')

class ParsedDateField(models.DateTimeField):
    def formfield(self, **kwargs):
        defaults = { 'form_class' : ParseDateForm }
        defaults.update(kwargs)
        return super(ParsedDateField, self).formfield(**defaults)

    def get_internal_type(self):
        return 'DateTimeField'

# Timespan - punt to another form page

class TimespanSearchForm(forms.ModelChoiceField):
    def __init__(self, *av, **kwargs):
        defaults = { 'widget' : TimespanWidget }
        defaults.update(kwargs)
        super(TimespanSearchForm, self).__init__(*av, **defaults)

class TimespanWidget(forms.Select):
    def render(self, name, value, attrs=None, choices=()):
        output = '<a href="'+settings.WWW_BASEURL+'timeperiod/add/">add timespan</a>'
        return mark_safe(output)

class TimespanField(models.ForeignKey):
    def formfield(self, **kwargs):
        defaults = { 'form_class' : TimespanSearchForm }
        defaults.update(kwargs)
        return super(TimespanField, self).formfield(**defaults)

# extents (of dataset) if data entry is needed ... 
# perhaps this all is superfluous :/
